package com.game.core.net.handler;

import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.game.message.protocol.ProtocolsConfig;

import io.netty.buffer.ByteBuf;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.ReferenceCountUtil;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
/*
 * https://trello.com/c/hGXF12yz/217-byte-byte-byte
 * 固定逻辑包头信息，进行业务识别。
 * 包头信息不正确则直接抛弃
 */
public class LengthLogicHandler extends ChannelDuplexHandler 
{
	private static final Logger logger = LoggerFactory.getLogger(LengthLogicHandler.class);
	final static byte LOGICFIELD = 12;  // 协议业务字段
	final static byte LOGICVERSION = 1; // 协议版本号
	AbstractMessageInitializer messageInitializer;
	
	public LengthLogicHandler(AbstractMessageInitializer messageInitializer)
	{
		this.messageInitializer = messageInitializer;
	}
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
	{
		if (msg instanceof ByteBuf)
		{
			ByteBuf inBuffer = (ByteBuf) msg;
			
			if (NioDatagramChannel.class.isAssignableFrom(ctx.channel().getClass()))
				ctx.fireChannelRead(msg);
			else
			{
				try
				{
					inBuffer.markReaderIndex();
					byte compress = inBuffer.readByte();
					int protocolID = inBuffer.readInt();
					int callback = inBuffer.readInt();
					logger.debug("LengthLogicHandler compress {} id {} callback {}", compress, protocolID, callback);
					if(protocolID == callback && 
					  (protocolID == ProtocolsConfig.P_CW_HEART_BEAT_REQ))
					{
						Class<?> msgClass = messageInitializer.getMessageClass(protocolID);
						Method method = msgClass.getDeclaredMethod("parseFrom", byte[].class);
						if (method != null)
						{
							byte[] array;
							int length = inBuffer.readableBytes();
							array = new byte[length];
							inBuffer.getBytes(inBuffer.readerIndex(), array, 0, length);
							method.invoke(null, array);
							
							// 解析旧协议成功，发送下一层
							inBuffer.resetReaderIndex();
							ctx.fireChannelRead(inBuffer);
						}
						else
							readChannel(ctx, inBuffer);
					}
					else
						readChannel(ctx, inBuffer);
				}
				catch(Exception exception)
				{
					readChannel(ctx, inBuffer);
				}
			}
		}
		else
		{
			ReferenceCountUtil.release(msg);
			logger.error("LengthLogicHandler found Illegal message format: expected byteBuf but {}", msg.getClass());
		}
	}
	
	private void readChannel(ChannelHandlerContext ctx, ByteBuf inBuffer)
	{
		inBuffer.resetReaderIndex();
		byte dataType = inBuffer.readByte();
		byte version = inBuffer.readByte();
		if (dataType == LOGICFIELD && version == LOGICVERSION)
		{
			ByteBuf outBuffer = ctx.alloc().buffer();
			outBuffer.writeBytes(inBuffer);
			ctx.fireChannelRead(outBuffer);
			ReferenceCountUtil.release(inBuffer);
		}
		else 
		{
			ReferenceCountUtil.release(inBuffer);
			logger.error("LengthLogicHandler Illegal message format, logic byte is error.");
		}
	}

	@Override
	public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception
	{
		if (msg instanceof ByteBuf)
		{
			ctx.write(msg, promise);
		}
		else
		{
			ReferenceCountUtil.release(msg);
			logger.error("LengthLogicHandler.write found Illegal message format: {}", msg.getClass());
        }
	}
}
